package com.smart.tool.log.impl;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.filter.PropertyPreFilter;

import com.smart.tool.log.SerializationLogger;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @Author gao.gwq
 * @Version SerializationUtils.java, v 0.1 2023年11月28日 20:28 gao.gwq
 * @Description: TODO
 */
public class FastJsonSerialization implements SerializationLogger {

    private static final Logger LOGGER = LoggerFactory.getLogger(FastJsonSerialization.class);
    private static final Map<Class, Map<String, Boolean>> SPECIAL_CLASS_PROPERTY_APPLY_MAP = new ConcurrentHashMap();





    public  String serialization(Object obj) {
        if (obj == null) {
            return null;
        }

        if (SPECIAL_CLASS_PROPERTY_APPLY_MAP.containsKey(obj.getClass())) {
            return serializationWithPropertyFilter(obj);
        }
        String result = null;
        try {
            result = JSON.toJSONString(obj);
        } catch (Throwable throwable) {
            LOGGER.error("SerializationUtils error class={}", Object.class.getName(), throwable);
            result = serializationWithPropertyFilter(obj);
        }

        return result;
    }

    /**
     * 序列化转为字符串的时候，如果某些字段是是有异常的字段，则不序列化，进行过滤防止打印日志影响主流程
     *
     * @param obj
     * @return
     */
    private static String serializationWithPropertyFilter(Object obj) {
        String result = null;
        if (obj == null) {
            return result;
        }
        try {
            result = JSON.toJSONString(obj, new PropertyPreFilter() {
                @Override
                public boolean process(JSONWriter writer, Object object, String name) {
                    //如果是map类型，则所有 的字段都可以进行转字符串
                    if (object instanceof Map) {
                        return true;
                    }

                    Map<String, Boolean> propertyApplyMap = (Map) FastJsonSerialization.SPECIAL_CLASS_PROPERTY_APPLY_MAP.get(object.getClass());
                    if (propertyApplyMap == null) {
                        synchronized (object.getClass()) {
                            propertyApplyMap = (Map) FastJsonSerialization.SPECIAL_CLASS_PROPERTY_APPLY_MAP.get(object.getClass());
                            if (propertyApplyMap == null) {
                                propertyApplyMap = new ConcurrentHashMap();
                                FastJsonSerialization.SPECIAL_CLASS_PROPERTY_APPLY_MAP.put(object.getClass(), propertyApplyMap);
                            }
                        }
                    }

                    Boolean isApply = (Boolean)((Map)propertyApplyMap).get(name);
                    if (isApply != null) {
                        return isApply;
                    }
                    try {
                        //尝试获取属性值，如果抛出异常，则改字段的get的方法会抛出异常
                        PropertyUtils.getProperty(object, name);
                        ((Map)propertyApplyMap).put(name, true);
                        return true;
                    } catch (Exception ex) {
                        ((Map)propertyApplyMap).put(name, false);
                        return false;
                    }
                }
            });
        } catch (Throwable throwable) {
            result = StringUtils.trimToEmpty(ToStringBuilder.reflectionToString(obj, ToStringStyle.SHORT_PREFIX_STYLE));
        }
        return result;
    }
}
